import { Scene } from './scene';
import { Game } from '../game';

export interface SceneOptions {
  key: string;
  scene: typeof Scene;
}

export interface SceneManagerOptions {
  scenes: SceneOptions[];
}

export class SceneManager {
  private scenes: Map<string, SceneOptions> = new Map();

  private game: Game;

  private availableScenes: Map<string, Scene> = new Map();

  private pausedScenes: Map<string, Scene> = new Map();

  private stopedScenes: Map<string, Scene> = new Map();

  constructor(options: SceneManagerOptions, game: Game) {
    this.game = game;

    const { scenes } = options;
    this.initScenes(scenes);
  }

  private initScenes (sceneOptions: SceneOptions[]) {
    for (const el of sceneOptions) {
      if (this.scenes.has(el.key)) {
        console.warn('duplicate scene key', el.key);
      } else {
        this.scenes.set(el.key, el);
      }
    }
  }

  start (key: string) {
    let sceneInstance: Scene;
    if (this.pausedScenes.has(key)) {
      sceneInstance = this.pausedScenes.get(key);
    } else {
      if (this.scenes.has(key)) {
        const sceneOption = this.scenes.get(key);
        sceneInstance = new sceneOption.scene(this.game);
      } else {
        console.error('failed to find scene by key.');
        return;
      }
    }

    this.availableScenes.set(key, sceneInstance);
  }

  pause (key: string) {
    const sceneInstance = this.availableScenes.get(key);
    if (sceneInstance) {
      this.pausedScenes.set(key, sceneInstance);
      this.availableScenes.delete(key);
    }
  }

  stop (key: string) {
    let sceneInstance : Scene;
    if (this.availableScenes.has(key)) {
      sceneInstance = this.availableScenes.get(key);
      this.availableScenes.delete(key);
    }

    if (this.pausedScenes.has(key)) {
      sceneInstance = this.pausedScenes.get(key);
      this.pausedScenes.delete(key);
    }

    this.stopedScenes.set(key, sceneInstance);
  }

  add (sceneOptions: SceneOptions) {
    if (this.scenes.has(sceneOptions.key)) {
      console.warn('duplicate scene key', sceneOptions.key);
    } else {
      this.scenes.set(sceneOptions.key, sceneOptions);
    }
  }

  remove (key: string) {
    if (this.scenes.has(key)) {
      this.stop(key);
      this.scenes.delete(key);
    } else {
      console.warn('scene key not found', key);
    }
  }

  update (elapsedTime: number) {
    this.availableScenes.forEach(scene => scene.update(elapsedTime));
  }

  render (canvasCtx: CanvasRenderingContext2D) {
    this.availableScenes.forEach(scene => scene.render(canvasCtx));
  }
}
